#pragma once
#include "zMatrixBase.hpp"

//for constant matrix like ones and zeros

namespace zzz{
template<typename T,class Major>
class zConstantMatrix : public zMatrixBaseR<T,Major>  //should not matter if rowmajor or colmajor
{
public:
  //constructor
  zConstantMatrix(zuint r, zuint c, T v):zMatrixBaseR<T,Major>(r,c),V_(v){}
  
  //operator()
  using zMatrixBaseR<T,Major>::operator();
  const T operator()(zuint r, zuint c) const {
    CheckRange(r, c);
    return V_;
  }
private:
  const T V_;
};

template<typename T>
inline const zConstantMatrix<T,zColMajor> Ones(zuint r, zuint c, const T& v=1) {
  return zConstantMatrix<T,zColMajor>(r,c,v);
}

inline const zConstantMatrix<double,zColMajor> Onesd(zuint r, zuint c, const double& v=1) {
  return zConstantMatrix<double,zColMajor>(r,c,v);
}

inline const zConstantMatrix<float,zColMajor> Onesf(zuint r, zuint c, const float& v=1) {
  return zConstantMatrix<float,zColMajor>(r,c,v);
}


template<typename T>
inline const zConstantMatrix<T,zColMajor> Zeros(zuint r, zuint c) {
  return zConstantMatrix<T,zColMajor>(r,c,0);
}

inline const zConstantMatrix<double,zColMajor> Zerosd(zuint r, zuint c) {
  return zConstantMatrix<double,zColMajor>(r,c,0);
}

inline const zConstantMatrix<float,zColMajor> Zerosf(zuint r, zuint c) {
  return zConstantMatrix<float,zColMajor>(r,c,0);
}

template<typename T,class Major>
class zConstantDiagMatrix : public zMatrixBaseR<T,Major> //should not matter if rowmajor or colmajor
{
public:
  //constructor
  explicit zConstantDiagMatrix(const zMatrixBaseR<T,Major> &mat)
  :zMatrixBaseR<T,Major>(mat.rows_,mat.rows_),Mat_(mat) {
    ZCHECK_EQ(mat.cols_, 1);
  }
  
  //operator()
  using zMatrixBaseR<T,Major>::operator();
  const T operator()(zuint r, zuint c) const {
    CheckRange(r, c);
    if (r==c) return Mat_(r,0);
    else return 0;
  }
private:
  const zMatrixBaseR<T,Major> &Mat_;
};

template<typename T,class Major>
const zConstantDiagMatrix<T,Major> Diag(const zMatrixBaseR<T,Major> &mat) {
  return zConstantDiagMatrix<T,Major>(mat);
}

template<typename T>
const zConstantDiagMatrix<T,zColMajor> Eye(int n, const T &v=1) {
  return zConstantDiagMatrix<T,zColMajor>(Ones<T>(n,1,v));
}

}
